package settings;

import logging.Logger;
import robot.*;

import java.awt.datatransfer.*;
import java.io.*;
import java.sql.Timestamp;
import java.util.*;

/**
 * Represents an executable and associated Workflow objects.
 * @author BDS
 */
public class Environment implements Serializable, Transferable
{
	private static final long serialVersionUID = 1L;

	private UUID id;
	private boolean enabled;
	private String name;
	private String path;
	private String argument1;
	private String argument2;
	private List<Workflow> workflows;

	/**
	 * Class constructor.
	 */
	public Environment()
	{
		id = UUID.randomUUID();
		enabled = true;
		name = "New environment";
		path = "";
		argument1 = "";
		argument2 = "";
		workflows = new ArrayList<Workflow>();
	}
	
	/**
	 * Copy constructor.
	 * @param environment The Environment to copy.
	 */
	public Environment(Environment environment)
	{
		id = UUID.randomUUID();
		enabled = environment.getEnabled();
		name = environment.getName();
		path = environment.getPath();
		argument1 = environment.getArgument1();
		argument2 = environment.getArgument2();
		workflows = new ArrayList<Workflow>(environment.getWorkflows().size());
		for (Workflow workflow : environment.getWorkflows())
		{
			workflows.add(new Workflow(workflow));
		}
	}

	/**
	 * Returns a String specific to the name.
	 * @return A String specific to the name.
	 */
	@Override
	public String toString() { return name; }

	/**
	 * Indicates whether the given Object is equivalent.
	 * @param environment Object to compare.
	 * @return True if the Object is equal; false otherwise.
	 */
	@Override
	public boolean equals(Object environment)
	{
		boolean equals = false;

		if ((environment instanceof Environment))
		{
			equals = id.equals(((Environment) environment).getID());
		}

		return equals;
	}
	
	/**
	 * Returns the hash code.
	 * @return The hash code.
	 */
	@Override
	public int hashCode()
	{
		int hashCode = 23;

	    hashCode = hashCode * 37 + id.hashCode();
	    hashCode = hashCode * 37 + name.hashCode();
	    hashCode = hashCode * 37 + path.hashCode();
	    hashCode = hashCode * 37 + argument1.hashCode();
	    hashCode = hashCode * 37 + argument2.hashCode();
	    hashCode = hashCode * 37 + Boolean.valueOf(enabled).hashCode();
	    
	    for (Workflow workflow : workflows)
	    {
	    	 hashCode = hashCode * 37 + workflow.hashCode();
	    }
	    
	    return hashCode;
	}
	
	/**
	 * Getter for the transferable data.
	 */
	@Override
	public Object getTransferData(DataFlavor dataFlavor) throws UnsupportedFlavorException, IOException
	{
		return this;
	}

	/**
	 * Getter for the supported transferable data flavors.
	 */
	@Override
	public DataFlavor[] getTransferDataFlavors()
	{
		return new DataFlavor[] { DataFlavor.stringFlavor };
	}

	/**
	 * Determines if the given DataFlavor is supported.
	 */
	@Override
	public boolean isDataFlavorSupported(DataFlavor dataFlavor)
	{
		return dataFlavor.equals(DataFlavor.stringFlavor);
	}

	/**
	 * Executes all Workflow objects for this Environment.
	 * @return The SessionResult for the execution.
	 */
	public SessionResult execute(ExecutionRobot robot)
	{
		SessionResult sessionResult = new SessionResult();
		sessionResult.setEnvironmentName(name);
		sessionResult.setStartTime(new Timestamp(System.currentTimeMillis()));
		
		try
		{
			// Execute all Workflow objects
			for (Workflow workflow : workflows)
			{
				if (!workflow.execute(robot))
				{
					sessionResult.setSuccess(false);
					break;
				}
			}
		}
		catch (Exception exception)
		{
			Logger.logException(exception);
			sessionResult.setSuccess(false);
		}

		sessionResult.setEndTime(new Timestamp(System.currentTimeMillis()));
		
		return sessionResult;
	}
	
	/**
	 * Determines if the Environment is valid.
	 * @return True if the Environment is valid; false otherwise.
	 */
	public boolean isValid()
	{
		return !name.equalsIgnoreCase("") && 
			   !path.equalsIgnoreCase("") && 
			   !argument1.equalsIgnoreCase("") && 
			   !argument2.equalsIgnoreCase("") && 
			   workflows != null;
	}

	/**
	 * Getter for the ID.
	 * @return The ID.
	 */
	public UUID getID() { return id; }
	
	/**
	 * Getter for the enabled flag.
	 * @return The enabled flag.
	 */
	public boolean getEnabled() { return enabled; }

	/**
	 * Setter for the enabled flag.
	 * @param enabled The enabled flag.
	 */
	public void setEnabled(boolean enabled) { this.enabled = enabled; }
	
	/**
	 * Getter for the name.
	 * @return The name.
	 */
	public String getName() { return name; }
	
	/**
	 * Setter for the name.
	 * @param name The name.
	 */
	public void setName(String name) { this.name = name; }
	
	/**
	 * Getter for the path.
	 * @return The path.
	 */
	public String getPath() { return path; }

	/**
	 * Setter for the path.
	 * @param path The path.
	 */
	public void setPath(String path) 
	{ 
		this.path = path;
	}
	
	/**
	 * Getter for the first command line argument.
	 * @return The first command line argument.
	 */
	public String getArgument1() { return argument1; }

	/**
	 * Setter for the first command line argument.
	 * @param argument1 The first command line argument.
	 */
	public void setArgument1(String argument1) { this.argument1 = argument1; }
	
	/**
	 * Getter for the second command line argument.
	 * @return The second command line argument.
	 */
	public String getArgument2() { return argument2; }

	/**
	 * Setter for the second command line argument.
	 * @param argument2 The second command line argument.
	 */
	public void setArgument2(String argument2) { this.argument2 = argument2; }
	
	/**
	 * Getter for the Workflow collection.
	 * @return The Workflow collection.
	 */
	public List<Workflow> getWorkflows() { return workflows; }
	
	/**
	 * Setter for the Workflow collection.
	 * @param workflows The Workflow collection.
	 */
	public void setWorkflows(List<Workflow> workflows) { this.workflows = workflows; }
}

